package org.base23.gateway.filter;

import com.fasterxml.jackson.databind.JsonNode;
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
import org.springframework.web.reactive.function.client.WebClient;
import org.springframework.web.reactive.function.client.WebClientResponseException;
import reactor.core.publisher.Mono;

@Component
public class ApiAuthGatewayFilterFactory extends
    AbstractGatewayFilterFactory<ApiAuthGatewayFilterFactory.Config> {

  private final WebClient.Builder webClientBuilder;

  public ApiAuthGatewayFilterFactory(WebClient.Builder webClientBuilder) {
    super(Config.class);
    this.webClientBuilder = webClientBuilder;
  }

  @Override
  public GatewayFilter apply(Config config) {
    return (exchange, chain) -> {
      // 访问 http://localhost:8085/internal/api-auth
      try {
        return webClientBuilder.baseUrl("http://localhost:8085")
            .build()
            .method(HttpMethod.GET)
            .uri("/internal/api-auth")
            .headers(headers -> headers.addAll(exchange.getRequest().getHeaders()))
            .retrieve()
            .bodyToMono(JsonNode.class)
            .flatMap(response -> {
              // 解析接口返回的数据
              int code = response.path("code").asInt();

              if (code == 0) {
                // 授权正常，将返回数据放到请求头
                JsonNode data = response.path("data");
                String userJson = data.toString();
                exchange.getRequest().mutate()
                    .header("user", userJson)
                    .build();
                // 继续请求链
                return chain.filter(exchange);
              } else {
                // code 不为 0，直接返回原文给前端
                exchange.getResponse().setStatusCode(HttpStatus.FORBIDDEN);
                return exchange.getResponse().writeWith(Mono.just(
                    exchange.getResponse().bufferFactory().wrap(response.toString().getBytes())));
              }
            })
            .onErrorResume(e -> {
              // 下游微服务返回的httpStatus不是200时，会跑到这里来。将下游返回的数据原文返回给前端
              if (e instanceof WebClientResponseException) {
                // 下游服务返回的httpStatus直接返回给客户端
                exchange.getResponse().setStatusCode(((WebClientResponseException) e).getStatusCode());
                // 下游返回的信息也直接返回给客户单
                return exchange.getResponse().writeWith(Mono.just(exchange.getResponse()
                    .bufferFactory().wrap(((WebClientResponseException) e).getResponseBodyAsByteArray())));
              } else {
                // 未知异常
                exchange.getResponse().setStatusCode(HttpStatus.INTERNAL_SERVER_ERROR);
                return exchange.getResponse().writeWith(Mono.just(exchange.getResponse()
                    .bufferFactory().wrap("{\"code\": 401, \"msg\": \"token verify fail!\", \"data\": null}".getBytes())));
              }
            });
      } catch (Exception e) {
        // 未知异常，返回自定义的 JSON 错误信息
        exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
        String errorMessage = "{\"code\": 401, \"msg\": \"token validate fail!\", \"data\": null}";
        return exchange.getResponse().writeWith(
            Mono.just(exchange.getResponse().bufferFactory().wrap(errorMessage.getBytes())));
      }
    };
  }

  public static class Config {
    // 可以扩展配置项
  }
}
